package com.jpm.jroguefx.types;

import com.jpm.jroguefx.factories.GraphicsFactory;
import javafx.scene.image.Image;

import java.util.logging.Level;
import java.util.logging.Logger;

public enum TerrainType {

    DESERTSEAE("L1_DesertShoreE"),
    DESERTSEAW("L1_DesertShoreW"),
    DESERTSEAN("L1_DesertShoreN"),
    DESERTSEAS("L1_DesertShoreS"),
    DESERTSEANE("L1_DesertShoreNE"),
    DESERTSEASE("L1_DesertShoreSE"),
    DESERTSEASW("L1_DesertShoreSW"),
    DESERTSEANW("L1_DesertShoreNW"),
    DESERTSEANEin("L1_DesertShoreNEin"),
    DESERTSEASWin("L1_DesertShoreSWin"),
    DESERTSEANWin("L1_DesertShoreNWin"),
    DESERTSEASEin("L1_DesertShoreSEin"),
    GRASSSEAE("L1_ShoreE"),
    GRASSSEAW("L1_ShoreW"),
    GRASSSEAN("L1_ShoreN"),
    GRASSSEAS("L1_ShoreS"),
    GRASSSEANE("L1_ShoreNE"),
    GRASSSEASE("L1_ShoreSE"),
    GRASSSEASW("L1_ShoreSW"),
    GRASSSEANW("L1_ShoreNW"),
    GRASSSEANEin("L1_ShoreNEin"),
    GRASSSEASWin("L1_ShoreSWin"),
    GRASSSEANWin("L1_ShoreNWin"),
    GRASSSEASEin("L1_ShoreSEin"),
    ICESEAE("L1_IceShoreE"),
    ICESEAW("L1_IceShoreW"),
    ICESEAN("L1_IceShoreN"),
    ICESEAS("L1_IceShoreS"),
    ICESEANE("L1_IceShoreNE"),
    ICESEASE("L1_IceShoreSE"),
    ICESEASW("L1_IceShoreSW"),
    ICESEANW("L1_IceShoreNW"),
    ICESEANEin("L1_IceShoreNEin"),
    ICESEASWin("L1_IceShoreSWin"),
    ICESEANWin("L1_IceShoreNWin"),
    ICESEASEin("L1_IceShoreSEin"),
    GRASSICEE("L1_SnowEdgeE"),
    GRASSICEW("L1_SnowEdgeW"),
    GRASSICEN("L1_SnowEdgeN"),
    GRASSICES("L1_SnowEdgeS"),
    GRASSICENE("L1_SnowEdgeNE"),
    GRASSICESE("L1_SnowEdgeSE"),
    GRASSICESW("L1_SnowEdgeSW"),
    GRASSICENW("L1_SnowEdgeNW"),
    GRASSICENEin("L1_SnowEdgeNEin"),
    GRASSICESWin("L1_SnowEdgeSWin"),
    GRASSICENWin("L1_SnowEdgeNWin"),
    GRASSICESEin("L1_SnowEdgeSEin"),
    GRASSDESERTE("L1_GrassDesertEdgeE"),
    GRASSDESERTW("L1_GrassDesertEdgeW"),
    GRASSDESERTN("L1_GrassDesertEdgeN"),
    GRASSDESERTS("L1_GrassDesertEdgeS"),
    GRASSDESERTNE("L1_GrassDesertEdgeNE"),
    GRASSDESERTSE("L1_GrassDesertEdgeSE"),
    GRASSDESERTSW("L1_GrassDesertEdgeSW"),
    GRASSDESERTNW("L1_GrassDesertEdgeNW"),
    GRASSDESERTNEin("L1_GrassDesertEdgeNEin"),
    GRASSDESERTSWin("L1_GrassDesertEdgeSWin"),
    GRASSDESERTNWin("L1_GrassDesertEdgeNWin"),
    GRASSDESERTSEin("L1_GrassDesertEdgeSEin"),
    ICE("L1_Terrain035"),
    GRASS("L1_Grass"),
    DESERT("L1_Terrain011"),
    UNKNOWN("L1_Terrain002"),
    GRASSHILL("L1_Terrain034"),
    DESERTHILL("L1_Terrain033"),
    ICEHILL("L1_Terrain039"),
    SEA("L1_Terrain005"),
    SEA2("L1_Terrain004"),
    ICEFOREST("L2_ForestPine03"),
    ICECOPSE("L2_ForestPine02"),
    ICETREE("L2_ForestPine01"),
    GRASSFOREST("L2_ForestMaple03"),
    GRASSCOPSE("L2_ForestMaple02"),
    GRASSTREE("L2_ForestMaple01"),
    DESERTFOREST("L2_ForestWillow03"),
    DESERTCOPSE("L2_ForestWillow02"),
    DESERTTREE("L2_ForestWillow01"),
    GRASSWOOD1("L2_TreePine01"),
    GRASSWOOD2("L2_TreePine02"),
    GRASSWOOD3("L2_TreePine03"),
    GRASSWOOD4("L2_TreePine04"),
    GRASSWOOD5("L2_TreePine05"),
    GRASSWOOD6("L2_TreePine06"),
    ICEWOOD1("L2_TreePine07"),
    ICEWOOD2("L2_TreePine08"),
    ICEWOOD3("L2_TreePine09"),
    ICEWOOD4("L2_TreePine10"),
    ICEWOOD5("L2_TreePine11"),
    ICEWOOD6("L2_TreePine12"),
    DESERTWOOD1("L2_TreeJungle01"),
    ICETREE1("L2_Terrain055"),
    ICETREE2("L2_Terrain056"),
    GRASSTREE1("L2_Terrain064"),
    GRASSTREE2("L2_Terrain065"),
    DESERTTREE1("L2_Terrain062"),
    DESERTTREE2("L2_Terrain063"),
    DESERTMOUNTAIN1("L2_MountainBigEarth01"),
    DESERTMOUNTAIN2("L2_MountainBigEarth02"),
    DESERTMOUNTAIN3("L2_MountainBigEarth03"),
    DESERTMOUNTAIN4("L2_MountainBigEarth04"),
    GRASSMOUNTAIN1("L2_MountainBigRock01"),
    GRASSMOUNTAIN2("L2_MountainBigRock02"),
    GRASSMOUNTAIN3("L2_MountainBigRock03"),
    GRASSMOUNTAIN4("L2_MountainBigRock04"),
    ICEMOUNTAIN1("L2_MountainBigSnow01"),
    ICEMOUNTAIN2("L2_MountainBigSnow02"),
    ICEMOUNTAIN3("L2_MountainBigSnow03"),
    ICEMOUNTAIN4("L2_MountainBigSnow04"),
    DESERTHOUSE1("L2_Terrain072"),
    DESERTHOUSE2("L2_Terrain073"),
    DESERTHOUSE3("L2_Terrain074"),
    DESERTHOUSE4("L2_Terrain075"),
    GRASSHOUSE1("L2_Terrain076"),
    GRASSHOUSE2("L2_Terrain077"),
    GRASSHOUSE3("L2_Terrain078"),
    GRASSHOUSE4("L2_Terrain080"),
    ICEHOUSE1("L2_Terrain088"),
    ICEHOUSE2("L2_Terrain089"),
    RIVERENDE("L2_RiverEndE"),
    RIVERENDN("L2_RiverEndN"),
    RIVERENDW("L2_RiverEndW"),
    RIVERENDS("L2_RiverEndS"),
    RIVERNS("L2_RiverNS"),
    RIVERWE("L2_RiverWE"),
    RIVERNE("L2_RiverNE"),
    RIVERNW("L2_RiverWN"),
    RIVERSE("L2_RiverSE"),
    RIVERSW("L2_RiverWS"),
    RIVERNSE("L2_RiverNSE"),
    RIVERWNE("L2_RiverWNE"),
    RIVERWNS("L2_RiverWNS"),
    RIVERWSE("L2_RiverWSE"),
    RIVERWNSE("L2_RiverWNSE"),
    ROADENDE("L2_RoadDirtEndE"),
    ROADENDN("L2_RoadDirtEndN"),
    ROADENDW("L2_RoadDirtEndW"),
    ROADENDS("L2_RoadDirtEndS"),
    ROADNS("L2_RoadDirtNS"),
    ROADWE("L2_RoadDirtWE"),
    ROADNE("L2_RoadDirtNE"),
    ROADNW("L2_RoadDirtWN"),
    ROADSE("L2_RoadDirtSE"),
    ROADSW("L2_RoadDirtWS"),
    ROADNSE("L2_RoadDirtNSE"),
    ROADWNE("L2_RoadDirtWNE"),
    ROADWNS("L2_RoadDirtWNS"),
    ROADWSE("L2_RoadDirtWSE"),
    ROADWNSE("L2_RoadDirtWNSE"),
    ICEBRIDGENS1("L2_BridgeSnowWEinEndE"),
    ICEBRIDGENS2("L2_BridgeSnowWEin"),
    ICEBRIDGENS3("L2_BridgeSnowWEinEndW"),
    ICEBRIDGENS4("L2_BridgeSnowWEoutEndE"),
    ICEBRIDGENS5("L2_BridgeSnowWEout"),
    ICEBRIDGENS6("L2_BridgeSnowWEoutEndW"),
    ICEBRIDGEEW1("L2_BridgeSnowNSinEndN"),
    ICEBRIDGEEW2("L2_BridgeSnowNSin"),
    ICEBRIDGEEW3("L2_BridgeSnowNSinEndS"),
    ICEBRIDGEEW4("L2_BridgeSnowNSoutEndN"),
    ICEBRIDGEEW5("L2_BridgeSnowNSout"),
    ICEBRIDGEEW6("L2_BridgeSnowNSoutEndS"),
    GRASSBRIDGENS1("L2_BridgeStoneNSinEndN"),
    GRASSBRIDGENS2("L1_BridgeStoneNSin"),
    GRASSBRIDGENS3("L2_BridgeStoneNSinEndS"),
    GRASSBRIDGENS4("L2_BridgeStoneNSoutEndN"),
    GRASSBRIDGENS5("L2_BridgeStoneNSout"),
    GRASSBRIDGENS6("L2_BridgeStoneNSoutEndS"),
    GRASSBRIDGEEW1("L2_BridgeStoneWEinEndW"),
    GRASSBRIDGEEW2("L1_BridgeStoneWEin"),
    GRASSBRIDGEEW3("L2_BridgeStoneWEinEndE"),
    GRASSBRIDGEEW4("L2_BridgeStoneWEoutEndW"),
    GRASSBRIDGEEW5("L2_BridgeStoneWEout"),
    GRASSBRIDGEEW6("L2_BridgeStoneWEoutEndE"),
    DESERTBRIDGENS1("L2_BridgeWoodNSinEndN"),
    DESERTBRIDGENS2("L1_BridgeWoodNSin"),
    DESERTBRIDGENS3("L2_BridgeWoodNSinEndS"),
    DESERTBRIDGENS4("L2_BridgeWoodNSoutEndN"),
    DESERTBRIDGENS5("L2_BridgeWoodNSout"),
    DESERTBRIDGENS6("L2_BridgeWoodNSoutEndS"),
    DESERTBRIDGEEW1("L2_BridgeWoodWEinEndW"),
    DESERTBRIDGEEW2("L1_BridgeWoodWEin"),
    DESERTBRIDGEEW3("L2_BridgeWoodWEinEndE"),
    DESERTBRIDGEEW4("L2_BridgeWoodWEoutEndW"),
    DESERTBRIDGEEW5("L2_BridgeWoodWEout"),
    DESERTBRIDGEEW6("L2_BridgeWoodWEoutEndE"),
    PLAYER("FemalePaladin01");

    private final Image image;
    private final GraphicsFactory gf = GraphicsFactory.getInstance();
    private final Logger logger = Logger.getLogger(TerrainType.class.getName());


    private TerrainType(String imgStr) {
        image = gf.get(imgStr);
        if (image == null) {
            logger.log(Level.SEVERE, "Failed to load image {0}", imgStr);
        }
    }

    public boolean isSameTerrain(TerrainType otherTerrain) {
        return otherTerrain != null && (getBaseTerrainType() == otherTerrain.getBaseTerrainType() || (this == SEA && otherTerrain == SEA2) || (this == SEA2 && otherTerrain == SEA));
    }

    public boolean isSea() {
        return (this == SEA || this == SEA2);
    }

    public Image getImage() {
        return image;
    }

    private TerrainType getBaseTerrainType() {
        if (this.ordinal() < 60) {
            switch (this.ordinal() / 12) {
                case 0:
                    return DESERT;
                case 1:
                case 4:
                    return GRASS;
                case 2:
                case 3:
                    return ICE;
            }
        }
        return this;
    }

    public TerrainType removeNarrows(TerrainType adjTerrain, short mask) {
        switch (mask) {
            case 0:
            case 194:
            case 66:
            case 98:
            case 192:
            case 2:
            case 64:
            case 224:
            case 96:
            case 102:
            case 226:
            case 8:
            case 56:
            case 25:
            case 24:
            case 57:
            case 40:
            case 41:
            case 9:
            case 3:
            case 7:
            case 6:
            case 152:
            case 16:
            case 20:
            case 156:
            case 28:
            case 144:
            case 148:
            case 1:
            case 4:
            case 32:
            case 128:
                return adjTerrain;
            default:
                return this;
        }
    }

    public TerrainType getEdging(TerrainType adjTerrain, short mask) {
        BorderType border = getBorderType(adjTerrain);

        if (border != null) {
            switch (mask) {
                case 23:
                case 22:
                case 151:
                case 150:
                    return getEdge(EdgeType.SW, border);
                case 31:
                case 63:
                case 159:
                case 191:
                    return getEdge(EdgeType.W, border);
                case 15:
                case 11:
                case 47:
                case 43:
                    return getEdge(EdgeType.NW, border);
                case 215:
                case 214:
                case 246:
                case 247:
                    return getEdge(EdgeType.S, border);
                case 111:
                case 107:
                case 235:
                case 239:
                    return getEdge(EdgeType.N, border);
                case 127:
                    return getEdge(EdgeType.SEin, border);
                case 223:
                    return getEdge(EdgeType.NEin, border);
                case 216:
                case 212:
                case 220:
                case 244:
                case 208:
                case 240:
                    return getEdge(EdgeType.SE, border);
                case 252:
                case 248:
                case 249:
                case 253:
                    return getEdge(EdgeType.E, border);
                case 254:
                    return getEdge(EdgeType.NWin, border);
                case 104:
                case 106:
                case 232:
                case 105:
                case 233:
                    return getEdge(EdgeType.NE, border);
                case 251:
                    return getEdge(EdgeType.SWin, border);

            }
        }
        return this;
    }


    private BorderType getBorderType(TerrainType otherTerrain) {

        switch (this) {
            case DESERT:
                switch (otherTerrain) {
                    case SEA:
                    case SEA2:
                        return BorderType.DESERTSEA;
                    default:
                        return null;
                }
            case GRASS:
                switch (otherTerrain) {
                    case DESERT:
                        return BorderType.GRASSDESERT;
                    case SEA:
                    case SEA2:
                        return BorderType.GRASSSEA;
                    default:
                        return null;
                }
            case ICE:
                switch (otherTerrain) {
                    case GRASS:
                        return BorderType.GRASSICE;
                    case SEA:
                    case SEA2:
                        return BorderType.ICESEA;
                    default:
                        return null;
                }
            default:
                return null;
        }
    }


    private TerrainType getEdge(EdgeType edgeType, BorderType borderType) {
        return values()[(edgeType.ordinal()) + (borderType.ordinal() * 12)];
    }

    public TerrainType getNext(int i) {
        return this.ordinal() < values().length - 1 ? values()[ordinal() + i] : null;
    }

    public boolean isMountain() {
        return (ordinal() >= DESERTMOUNTAIN1.ordinal() && ordinal() <= ICEMOUNTAIN4.ordinal());
    }

    public boolean isHouse() {
        return (ordinal() >= DESERTHOUSE1.ordinal() && ordinal() <= ICEHOUSE2.ordinal());
    }

    public static TerrainType getRiver(short mask) {

        //System.out.println("RIVER MASK "+ mask);

        switch (mask) {
            case 1:
            case 8:
            case 9:
                return RIVERNS;
            case 2:
            case 4:
            case 6:
                return RIVERWE;
            case 3:
                return RIVERNE;
            case 5:
                return RIVERNW;
            case 10:
                return RIVERSE;
            case 12:
                return RIVERSW;
            case 11:
                return RIVERNSE;
            case 7:
                return RIVERWNE;
            case 14:
                return RIVERWSE;
            case 13:
                return RIVERWNS;
            case 15:
                return RIVERWNSE;
            default:
                return null;

        }
    }

    public static TerrainType getRoad(short mask) {
        TerrainType river = getRiver(mask);
        return values()[river.ordinal() - RIVERENDE.ordinal() + ROADENDE.ordinal()];
    }

    public static TerrainType getBridge(TerrainType baseTerrain, boolean nswe) {
        return values()[((baseTerrain.getBaseTerrainType().ordinal() - ICE.ordinal()) * 12) + ICEBRIDGENS1.ordinal() + (nswe ? 0 : 6)];
    }


}
